import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.concurrent.ArrayBlockingQueue;

import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class ChatFrame  extends JFrame implements ActionListener{

	private static final long serialVersionUID = 1L;
	private JPanel chatBoxPane = new JPanel();
	private final Container pane = getContentPane();
	private JTextField inputTextField;
	private static User user = null;
	private ArrayList<User> receipients = null;
	private ArrayBlockingQueue<Message> queue = new ArrayBlockingQueue<>(1024);
	private Long msgIDCounter = 0L;
	private Hashtable<String, NormalMessage> msgBuffer;
	private Hashtable<String, Long> msgIDDelivered;
	private Hashtable<Long, TotalMessage> totalBuffer;
	private long totalCurrentID = -1;

	public static User getUser() {
		return user;
	}

	public Hashtable<String, Long> getMsgIDDelivered() {
		return msgIDDelivered;
	}

	public void setMsgIDDelivered(Hashtable<String, Long> msgIDDelivered) {
		this.msgIDDelivered = msgIDDelivered;
	}

	public Long getMsgIDCounter() {
		return msgIDCounter;
	}

	public void setMsgIDCounter(Long msgIDCounter) {
		this.msgIDCounter = msgIDCounter;
	}

	public Hashtable<String, NormalMessage> getMsgBuffer() {
		return msgBuffer;
	}

	public void setMsgBuffer(Hashtable<String, NormalMessage> msgBuffer) {
		this.msgBuffer = msgBuffer;
	}

	public ChatFrame(User user) {
		super(user.getName());
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		chatBoxPane.setLayout(new BoxLayout(chatBoxPane, BoxLayout.Y_AXIS));
		pane.add(chatBoxPane, BorderLayout.CENTER);
		
		inputTextField = new JTextField(50);
		inputTextField.addActionListener(this);
		pane.add(inputTextField, BorderLayout.PAGE_END);
		
		setSize(300, 500);
		setResizable(false);
		setVisible(true);
		setReceipientsToAll();
		msgBuffer = new Hashtable<>();
		msgIDDelivered = new Hashtable<>();
		totalBuffer = new Hashtable<>();
		for (User u : Configuration.getInstance().getUsers()) {
			msgIDDelivered.put(u.getName(), -1L);
		}
	}
	
	public ArrayBlockingQueue<Message> getQueue() {
		return queue;
	}

	public void addQueue(AckMessage aMsg) {
		queue.add(aMsg);
	}
	
	public void actionPerformed(ActionEvent evt) {
        String text = inputTextField.getText();
        if (text.equals("")) {
        	return;
        }
        inputTextField.setText("");

		for(User r : receipients) {
			NormalMessage msg = new NormalMessage(text, user);
			new Sender(msg, r, queue, msgIDCounter.longValue());
			msgIDCounter++;
		}
    }
	
	public void addTextToChat(NormalMessage msg) {
		if (chatBoxPane.getComponentCount() > 27) {
			chatBoxPane.remove(0);
		}
		String senderName = "";
		if (msg.getSender().getName().equalsIgnoreCase(user.getName())) {
			senderName = "Me";
		} else {
			senderName = msg.getSender().getName();
		}
		String label = senderName + ": " + msg.getContent();
        JLabel newLabel = new JLabel(label);
        chatBoxPane.add(newLabel);
        chatBoxPane.validate();
	}
	
	public void bDeliver(NormalMessage msg) throws InterruptedException {
		long senderID = msg.getSenderID();
		String sender = msg.getSender().getName();
		String msgKey = sender+"@"+senderID;
		if (senderID > msgIDDelivered.get(sender) && !msgBuffer.containsKey(msgKey)) {
				msgBuffer.put(msgKey, msg);
		}
		
		boolean continued = true;
		while (continued) {
			continued = false;
			for (String key : msgBuffer.keySet()) {
				String[] str = key.split("@");
				String name = str[0];
				long id = Long.parseLong(str[1]);
				if (id/Configuration.getInstance().getUsers().size()==msgIDDelivered.get(sender).longValue()+1 && name.equalsIgnoreCase(sender)) {
					addTextToChat(msgBuffer.get(key));
					msgIDDelivered.put(sender,id/Configuration.getInstance().getUsers().size());
					msgBuffer.remove(key);
					continued = true;
					break;
				}
			}
		}
		
	}
	
	public void totalDeliver(TotalMessage msg) {
		System.out.println("TotalMessageDeliver " + msg.getContent());
		if (msg.getSequenceID() > totalCurrentID && !totalBuffer.containsKey(msg.getSequenceID())) {
			totalBuffer.put(msg.getSequenceID(), msg);
		}
		while (totalBuffer.containsKey(totalCurrentID+1)) {
			totalCurrentID++;
			//totalBuffer.get(totalCurrentID).getSender().setName("Total" + totalCurrentID);
			addTextToChat(totalBuffer.get(totalCurrentID));
		}
	}
	
	public void setReceipients(ArrayList<User> receipients) {
		this.receipients = receipients;
	}
	
	public void setReceipientsToAll() {
		setReceipients(Configuration.getInstance().getUsers());
	}
	
	public static void main(String[] args) throws Exception {
		String name = args[0];
		user = Configuration.getInstance().getUserByName(name);
		ChatFrame cFrame = new ChatFrame(user);
		new Listener(user, cFrame);
	}
}
